package cn.bitkit.base.util;

import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

/**
 * 
 * @author changbo
 * 
 */
@Slf4j
public class DateUtil {
	
    public static String toDate(Date date){
    	return format(date, LocalDateTimeUtil.DF_DATE);
    }
    
    public static String toDateTime(Date date){
    	return format(date, LocalDateTimeUtil.DF_DATE_TIME);
    }
    
    public static String toTimestamp(Date date){
    	return format(date, LocalDateTimeUtil.DF_DATE_TIME_MS);
    }
    
    public static String toDateNum(Date date){
    	return format(date, LocalDateTimeUtil.DF_DATE_NUM);
    }
    
    public static String toDateTimeNum(Date date){
    	return format(date, LocalDateTimeUtil.DF_DATE_TIME_NUM);
    }

	public static String toDateTimeMsNum(Date date){
		return format(date, LocalDateTimeUtil.DF_DATE_TIME_MS_NUM);
	}

	public static String toYearMonthNum(Date date){
		return format(date, LocalDateTimeUtil.DF_YEAR_MONTH_NUM);
	}

    public static String getCurrentDate(){
    	return toDateTime(new Date());
    }
    
    public static String getCurrentDateNum(){
    	return toDateNum(new Date());
    }
    
    public static String getCurrentTime(){
    	return toDateTime(new Date());
    }
    public static String getCurrentTimeNum(){
    	return toDateTimeNum(new Date());
    }

	public static String getCurrentTimeMsNum(){
		return toDateTimeMsNum(new Date());
	}

	public static String format(Date date, DateTimeFormatter formatter) {
		try {
			if(formatter == null || date == null) {
				return null;
			}
			LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
			return localDateTime.format(formatter);
		} catch (Exception e) {
			log.error("", e);
		}
		return null;
	}

	public static String format(Date date, String format) {
		return format(date, DateTimeFormatter.ofPattern(format));
	}

	public static Date parseDate(String format, String date) {
		return parseDate(DateTimeFormatter.ofPattern(format), date);
	}

	public static Date parseDateTime(String format, String date) {
		return parseDateTime(DateTimeFormatter.ofPattern(format), date);
	}

	private static Date parseDateTime(DateTimeFormatter formatter, String date) {
		try {
			if(formatter == null || date == null) {
				return null;
			}
			LocalDateTime localDateTime = LocalDateTime.parse(date, formatter);
			return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
		} catch (Exception e) {
			log.error("", e);
		}
		return null;
	}

	private static Date parseDate(DateTimeFormatter formatter, String date) {
		try {
			if(formatter == null || date == null) {
				return null;
			}
			LocalDate localDate = LocalDate.parse(date, formatter);
			return Date.from(localDate.atTime(LocalTime.MIN).atZone(ZoneId.systemDefault()).toInstant());
		} catch (Exception e) {
			log.error("", e);
		}
		return null;
	}
    
    public static Date parseDate(String date){
    	return parseDate(LocalDateTimeUtil.DF_DATE, date);
    }
    
    public static Date parseDateTime(String date){
    	return parseDateTime(LocalDateTimeUtil.DF_DATE_TIME, date);
    }
    
    public static Date parseDateNum(String date){
    	return parseDate(LocalDateTimeUtil.DF_DATE_NUM, date);
    }
    
    public static Date parseDateTimeNum(String date){
    	return parseDateTime(LocalDateTimeUtil.DF_DATE_TIME_NUM, date);
    }
    
	public static Date add(Date date, int field, int addValue){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(field, addValue);
		return calendar.getTime();
	}

    public static Date addYears(Date date, int years){
		return add(date, Calendar.YEAR, years);
    }

    public static Date addMonths(Date date, int months){
		return add(date, Calendar.MONTH, months);
    }
    
    public static Date addDays(Date date, int days){
		return add(date, Calendar.DAY_OF_YEAR, days);
    }
    
    public static int getYear(Date date){
    	Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.YEAR);
    }
    
    public static int getMonth(Date date){
    	Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.MONTH)+1;
    }

    public static int getDay(Date date){
    	Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.DAY_OF_MONTH);
    }
    

    public static Date getDateTime(Date date, int hour, int minute, int second, int milliSecond) {
    	if(date == null){
    		return null;
    	}
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(date);
    	cal.set(Calendar.HOUR_OF_DAY, hour);
    	cal.set(Calendar.MINUTE, minute);
    	cal.set(Calendar.SECOND, second);
    	cal.set(Calendar.MILLISECOND, milliSecond);
    	return cal.getTime();
    }
    
    public static Date getDayStart(Date date){
    	return getDateTime(date, 0, 0, 0, 0);
    }
    
    public static Date getDayEnd(Date date){
    	return getDateTime(date, 23, 59, 59, 999);
    }
    
    public static Date getMonthStart(Date date){
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(date);
		cal.set(Calendar.DAY_OF_MONTH, 1);
    	cal.set(Calendar.HOUR_OF_DAY, 0);
    	cal.set(Calendar.MINUTE, 0);
    	cal.set(Calendar.SECOND, 0);
    	cal.set(Calendar.MILLISECOND, 0);
		return cal.getTime();
    }

    public static Date getMonthEnd(Date date){
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(date);
    	cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
    	cal.set(Calendar.HOUR_OF_DAY, 23);
    	cal.set(Calendar.MINUTE, 59);
    	cal.set(Calendar.SECOND, 59);
    	cal.set(Calendar.MILLISECOND, 999);
		return cal.getTime();
    }
    
    public static int getDays(Date date1, Date date2){
    	if(date1 == null || date2 == null){
    		throw new RuntimeException();
    	}
    	date1 = getDayStart(date1);
    	date2 = getDayStart(date2);
    	long time = date1.getTime() - date2.getTime();
    	return (int)(time/(24*60*60*1000));
    }
    
    public static int getWeekDay(Date date){
    	Calendar cal = Calendar.getInstance();
    	cal.setTime(date);
    	int wd = cal.get(Calendar.DAY_OF_WEEK) -1;
    	wd = (wd == 0) ? 7 : wd;
    	return wd;
    }

    
}
